package com.lmm.http.client;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.protocol.RequestAcceptEncoding;
import org.apache.http.client.protocol.ResponseContentEncoding;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

public class HttpClientUtils {

	/**
	 * 总连接数
	 */
	private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 100;

	/**
	 * 路由最大连接数
	 */
	private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 10;

	/**
	 * 建立连接超时时限
	 */
	private static final int SO_TIMEOUT = 20 * 1000;

	/**
	 * 读取数据超时时限
	 */
	private static final int REQUEST_TIMEOUT = 60 * 1000;
	// private static Logger log =
	// LoggerFactory.getLogger(HttpClientUtils.class);
	private static PoolingClientConnectionManager connManager = null;

	private static DefaultHttpClient httpclient = null;
	/**
	 * 默认按字符串处理
	 */
	private static BasicResponseHandler basicResponseHandler = null;

	static {

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory
				.getSocketFactory()));
		schemeRegistry.register(new Scheme("https", 443, SSLSocketFactory
				.getSocketFactory()));
		connManager = new PoolingClientConnectionManager(schemeRegistry);
		connManager.setMaxTotal(DEFAULT_MAX_TOTAL_CONNECTIONS);
		connManager.setDefaultMaxPerRoute(DEFAULT_MAX_CONNECTIONS_PER_ROUTE);
		HttpParams params = new BasicHttpParams();
		params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
				HttpVersion.HTTP_1_1);
		// 建立连接超时时限
		params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
				REQUEST_TIMEOUT);
		// 读取数据超时时限
		params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SO_TIMEOUT);
		httpclient = new DefaultHttpClient(connManager, params);
		registerGizp(httpclient);
		basicResponseHandler = new BasicResponseHandler() {

			/*
			 * (non-Javadoc)
			 * 
			 * @see
			 * org.apache.http.impl.client.BasicResponseHandler#handleResponse
			 * (org.apache.http.HttpResponse)
			 */
			@Override
			public String handleResponse(HttpResponse response)
					throws HttpResponseException, IOException {
				StatusLine statusLine = response.getStatusLine();
				HttpEntity entity = response.getEntity();
				if (statusLine.getStatusCode() >= 300) {
					EntityUtils.consume(entity);
					throw new HttpResponseException(statusLine.getStatusCode(),
							statusLine.getReasonPhrase());
				}
				return entity == null ? null : EntityUtils.toString(entity,
						"utf-8");
			}

		};
	}

	public static DefaultHttpClient getHttpClient() {
		return httpclient;
	}


	/**
	 * 注册gzip压缩
	 * 
	 * @param httpclient
	 */
	@SuppressWarnings("deprecation")
	private static void registerGizp(DefaultHttpClient httpclient) {
	/*	httpclient.addRequestInterceptor(new HttpRequestInterceptor() {
			public void process(final HttpRequest request,
					final HttpContext context) throws HttpException,
					IOException {
				if (!request.containsHeader("Accept-Encoding")) {
					request.addHeader("Accept-Encoding", "gzip,deflate,sdch");
				}
			}

		});

		httpclient.addResponseInterceptor(new HttpResponseInterceptor() {
			public void process(final HttpResponse response,
					final HttpContext context) throws HttpException,
					IOException {
				HttpEntity entity = response.getEntity();
				Header ceheader = entity.getContentEncoding();
				if (ceheader != null) {
					HeaderElement[] codecs = ceheader.getElements();
					for (int i = 0; i < codecs.length; i++) {
						if (codecs[i].getName().equalsIgnoreCase("gzip")) {
							response.setEntity(new GzipDecompressingEntity(
									response.getEntity()));
							return;
						}
					}
				}
			}

		});*/
		 httpclient.addRequestInterceptor(new RequestAcceptEncoding());
		 httpclient.addResponseInterceptor(new ResponseContentEncoding());
	}

	public static void release() {
		if (connManager != null) {
			connManager.shutdown();
		}
	}

	public static void main(String[] args) throws ClientProtocolException,
			IOException, URISyntaxException {
		Random r = new Random();
		for (int i = 0; i < 10; i++) {
			long l1 = System.currentTimeMillis();
			//String url = "http://127.0.0.1:8080/test3/test.jsp";
			String url = "http://stage.zt906.com/api/mobile/user.pfv";
			String auth="6YKT5LiJ5LiJOkY1OUJENjVGN0VEQUZCMDg3QTgxRDREQ0EwNkM0OTEw";
			Map<String,String> headerParams = new HashMap<String, String>();
			headerParams.put("Auth", auth);
			Map<String, String> params = new HashMap<String, String>();
			params.put("random", String.valueOf(r.nextInt(50000)));
			String content = execute("get", url, headerParams, params);
			System.out.println("content:"+content);
			System.out.println("查询耗时" + (System.currentTimeMillis() - l1));
		}
	}

	/**
	 * 
	 * @param httpMethod
	 *            请求类型
	 * @param url
	 *            请求url
	 * @param headerParams
	 *            请求头
	 * @param params
	 *            请求参数
	 * @return
	 * @throws RuntimeException
	 */
	 public static String execute(String httpMethod, String url,
			Map<String, String> headerParams, Map<String, String> params)
			throws RuntimeException {
		String content = null;
		HttpRequestBase req = null;
		try {
			req = createHttpUriRequest(httpMethod, url,headerParams, params);
			content = httpclient.execute(req, basicResponseHandler);
		} catch (URISyntaxException e) {
			throw new RuntimeException(e.getMessage());
		} catch (ClientProtocolException e) {
			throw new RuntimeException(e.getMessage());
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage());
		} finally {
			if (req != null)
				req.releaseConnection();
		}

		return content;

	}

	 /**
		 * 
		 * @param httpMethod
		 *            请求类型
		 * @param url
		 *            请求url
		 * @param headerParams
		 *            请求头
		 * @param params
		 *            请求参数
		 * @return
		 * @throws URISyntaxException
		 * @throws IOException
		 * @throws ClientProtocolException
		 */
		 public static String executeMany(String httpMethod, String url,
				Map<String, String> headerParams, Map<String, String[]> params)
				throws RuntimeException {
			String content = null;
			HttpRequestBase req = null;
			try {
				req = createHttpUriRequestParamsMany(httpMethod, url,headerParams, params);
				content = httpclient.execute(req, basicResponseHandler);
			} catch (URISyntaxException e) {
				throw new RuntimeException(e.getCause());
			} catch (ClientProtocolException e) {
				throw new RuntimeException(e.getCause());
			} catch (IOException e) {
				throw new RuntimeException(e.getCause());
			} finally {
				if (req != null)
					req.releaseConnection();
			}

			return content;

		}
	
	/**
	 * 
	 * @param httpMethod
	 *            请求类型
	 * @param url
	 *            请求url
	 * @param headerParams
	 *            请求头参数
	 * @param params
	 *            请求参数
	 * @return
	 * @throws URISyntaxException
	 */
	private static HttpRequestBase createHttpUriRequest(String httpMethod,
			String url, Map<String, String> headerParams,
			Map<String, String> params) throws URISyntaxException {
		HttpMethod hMethod = HttpMethod.toHttpMethod(httpMethod.toLowerCase());
		if (!HttpMethod.POST.equals(hMethod)) {// 如果不是post请求，将参数传到url后面
			url = registerUrlParams(url, params);
		}
		// 加上时戳
		registerUrlTimeStamp(url);
		HttpRequestBase req = createHttpUriRequest(hMethod, new URI(url));
		// 添加头信息
		registerHeader(req, headerParams);
		if (HttpMethod.POST.equals(hMethod)) {// 如果是post请求，将参数传到url后面
			registerPostParams((HttpPost) req, params);
		}
		return req;
	}

	

	/**
	 * 
	 * @param httpMethod
	 * @param url
	 * @param headerParams
	 * @param params
	 * @return
	 * @throws URISyntaxException
	 */
	private static HttpRequestBase createHttpUriRequestParamsMany(
			String httpMethod, String url, Map<String, String> headerParams,
			Map<String, String[]> params) throws URISyntaxException {
		HttpMethod hMethod = HttpMethod.toHttpMethod(httpMethod.toLowerCase());

		if (!HttpMethod.POST.equals(hMethod)) {// 如果不是post请求，将参数传到url后面
			url = registerUrlParamsMany(url, params);
		}
		// 加上时戳
		registerUrlTimeStamp(url);
		HttpRequestBase req = createHttpUriRequest(hMethod, new URI(url));
		// 添加头信息
		registerHeader(req, headerParams);
		if (HttpMethod.POST.equals(hMethod)) {// 如果是post请求，将参数传到url后面
			registerPostParamsMany((HttpPost) req, params);
		}

		return req;
	}


	/**
	 * 注册头信息
	 * 
	 * @param req
	 * @param headerParams
	 */
	private static void registerHeader(HttpUriRequest req,
			Map<String, String> headerParams) {
		// 设置HEADER信息
		if (headerParams != null) {
			for (Map.Entry<String, String> e : headerParams.entrySet()) {
				String key = e.getKey();
				String value = e.getValue();
				req.addHeader(key, value);
			}
		}
	}

	/**
	 * 向url添加时戳
	 * 
	 * @param url
	 * @return
	 */
	private static String registerUrlTimeStamp(String url) {
		StringBuffer sb = new StringBuffer(url);
		// 如果没有参数
		if (url.indexOf("?") == -1) {// 如果已经存在参数
			sb.append("?");
			// 如果最后一个不是'&'字符
		} else if (!"&".equals(url.substring(url.length() - 1))) {
			sb.append("&");
		}
		// 加上时戳
		sb.append("_t=").append(new Date().getTime());
		return sb.toString();
	}

	/**
	 * 注册url请求参数
	 * 
	 * @param url
	 *            请求url
	 * @param params
	 *            请求参数
	 */
	private static String registerUrlParams(String url,
			Map<String, String> params) {
		StringBuffer sb = new StringBuffer(url);
		// 如果没有参数
		if (params == null || params.size() == 0) {
			return url;
		}
		if (url.indexOf("?") == -1) {// 如果已经存在参数
			sb.append("?");
			// 如果最后一个不是'&'字符
		} else if (!"&".equals(url.substring(url.length() - 1))) {
			sb.append("&");
		}
		for (Map.Entry<String, String> e : params.entrySet()) {
			sb.append(e.getKey()).append("=").append(e.getValue());
			sb.append("&");

		}// end for(Map.Entry<String, String[]> e:params.entrySet()){
			// 去掉最后一个&字符
		return sb.substring(0, sb.length() - 1);
	}

	/**
	 * 注册url请求参数
	 * 
	 * @param url
	 * @param params
	 */
	private static String registerUrlParamsMany(String url,
			Map<String, String[]> params) {
		StringBuffer sb = new StringBuffer(url);
		// 如果没有参数
		if (params == null || params.size() == 0) {
			return url;
		}
		if (url.indexOf("?") == -1) {// 如果已经存在参数
			sb.append("?");
			// 如果最后一个不是'&'字符
		} else if (!"&".equals(url.substring(url.length() - 1))) {
			sb.append("&");
		}
		for (Map.Entry<String, String[]> e : params.entrySet()) {
			for (String t : e.getValue()) {
				sb.append(e.getKey()).append("=").append(t);
				sb.append("&");
			}// end for(String t:e.getValue()){
		}// end for(Map.Entry<String, String[]> e:params.entrySet()){
			// 去掉最后一个&字符
		return sb.substring(0, sb.length() - 1);
	}

	/**
	 * 注册post参数信息
	 * 
	 * @param req
	 *            请求对象
	 * @param params
	 *            请求参数
	 */
	private static void registerPostParams(HttpPost req,
			Map<String, String> params) {
		if (params != null && params.size() > 0) {
			// 设置POST提交参数
			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
			for (Map.Entry<String, String> e : params.entrySet()) {
				String key = e.getKey();
				NameValuePair nvp = new BasicNameValuePair(key, e.getValue());
				nvps.add(nvp);
			}
			try {
				req.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
			} catch (UnsupportedEncodingException ignore) {
			}
		}

	}

	/**
	 * 注册post参数信息
	 * 
	 * @param req
	 *            请求对象
	 * @param params
	 *            请求参数
	 */
	private static void registerPostParamsMany(HttpPost req,
			Map<String, String[]> params) {
		// 设置POST提交参数
		List<NameValuePair> nvps = new ArrayList<NameValuePair>();
		if (params != null && params.size() > 0) {
			for (Map.Entry<String, String[]> e : params.entrySet()) {
				String key = e.getKey();
				for (String t : e.getValue()) {
					NameValuePair nvp = new BasicNameValuePair(key, t);
					nvps.add(nvp);
				}// end for(String t:e.getValue()){
			}
		}
		try {
			req.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
		} catch (UnsupportedEncodingException ignore) {
		}
	}

	/**
	 * Create a Commons HttpMethodBase object for the given HTTP method and URI
	 * specification.
	 * 
	 * @param httpMethod
	 *            the HTTP method
	 * @param uri
	 *            the URI
	 * @return the Commons HttpMethodBase object
	 */
	public static HttpRequestBase createHttpUriRequest(HttpMethod httpMethod,
			URI uri) {
		switch (httpMethod) {
		case GET:
			return new HttpGet(uri);
		case DELETE:
			return new HttpDelete(uri);
		case HEAD:
			return new HttpHead(uri);
		case OPTIONS:
			return new HttpOptions(uri);
		case POST:
			return new HttpPost(uri);
		case PUT:
			return new HttpPut(uri);
		case TRACE:
			return new HttpTrace(uri);
		default:
			throw new IllegalArgumentException("Invalid HTTP method: "
					+ httpMethod);
		}
	}

	/**
	 * 
	 * @author leiming
	 *
	 */
	public enum HttpMethod {
		GET("get"), POST("post"), HEAD("head"), OPTIONS("options"), PUT("put"), DELETE(
				"delete"), TRACE("trace");

		private String method;// 请求方法

		HttpMethod(String method) {
			this.method = method;
		}

		/**
		 * @return the method
		 */
		public String getMethod() {
			return method;
		}

		public static HttpMethod toHttpMethod(String method) {
			method = method.toLowerCase();
			for (HttpMethod t : HttpMethod.values()) {
				if (t.getMethod().equals(method)) {
					return t;
				}
			}
			return null;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Enum#toString()
		 */
		@Override
		public String toString() {
			String str = this.method + ":" + this.ordinal();
			return str;
		}

	}
}